using System.Collections.Generic;
using Microsoft.Xna.Framework;
using SkinningInformation;
using System;
using GameEngine.Navigation;

namespace GameEngine.Units
{
	public class Unit : Grounded
	{
		private UnitType type;
		private AIScript aiScript;

		public Unit(UnitType type, World world)
			: base(type, world)
		{
			this.type = type;
		}

		public float HitPoints { get; internal set; }
		public float MaxHitPoints
		{
			get
			{
				return this.type.MaxHitPoints;
			}
		}
		public bool IsDead { get; internal set; }
		// indicates the unit died and its corpse decayed over time it is ready to completely pass away...
		public bool IsDecayed { get; internal set; }
		public float MovementSpeed
		{
			get
			{
				return this.type.MovementSpeed;
			}
		}

		// TODO: this should be private and there should be other way of issueing orders rather than setting this...
		public Action Action { get; set; }
		public bool IsIdle
		{
			get
			{
				return this.Action == null;
			}
		}
		public bool IsMoving { get; private set; }
		public AIScript AIScript
		{
			get
			{
				return this.aiScript;
			}
			set
			{
				if (value != null && value != this.aiScript)
				{
					value.Owner = this;
					this.aiScript = value;
				}
			}
		}

		public void MoveTo(WayPoint position)
		{
			this.IsMoving = true;
			this.Action = new MoveTo(this, position, 0);
		}
		public void MoveTo(WayPoint position, float distance)
		{
			this.IsMoving = true;
			this.Action = new MoveTo(this, position, distance);
		}
		public void MoveTo(Unit target)
		{
			this.IsMoving = true;
			this.Action = new MoveTo(this, target, 0);
		}
		public void MoveTo(Unit target, float distance)
		{
			this.IsMoving = true;
			this.Action = new MoveTo(this, target, distance);
		}

		internal override void Update(GameTime gameTime)
		{
			if (this.Action != null)
			{
				if (this.Action.Update(ref gameTime))
				{
					this.Action = null;
					this.IsMoving = false;
					this.PlayAnimation("Idle");
				}
			}
			if (this.AIScript != null)
			{
				this.AIScript.Update(ref gameTime);
			}
		}

		internal void UpdateWayPoint()
		{
			double wayPointDistance = Vector3.Distance(this.Position, this.WayPoint.Position);
			foreach (WayPoint neighbour in this.WayPoint.Neighbours)
			{
				double newWayPointDistance = Vector3.Distance(neighbour.Position, this.Position);
				if (newWayPointDistance < wayPointDistance)
				{
					this.WayPoint = neighbour;
					wayPointDistance = newWayPointDistance;
				}
			}
		}

		internal bool CanMoveTo(Vector3 position)
		{
			return this.World.CanMoveTo(this, position);
		}
	}
}
